knitr::opts_chunk$set(warning = FALSE, message = FALSE)
library(devtools)
Loading required package: usethis
library(ExPanDaR)
Registered S3 methods overwritten by 'htmltools':
  method               from         
  print.html           tools:rstudio
  print.shiny.tag      tools:rstudio
  print.shiny.tag.list tools:rstudio
Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     
library(knitr)
library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
-- Attaching packages --------------------------------------- tidyverse 1.3.0 --
v ggplot2 3.3.0     v purrr   0.3.4
v tibble  3.0.1     v dplyr   1.0.2
v tidyr   1.0.3     v stringr 1.4.0
v readr   1.3.1     v forcats 0.5.0
-- Conflicts ------------------------------------------ tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
library(modelr)
library(broom)

Attaching package: 㤼㸱broom㤼㸲

The following object is masked from 㤼㸱package:modelr㤼㸲:

    bootstrap
library(data.table)
data.table 1.12.8 using 2 threads (see ?getDTthreads).  Latest news: r-datatable.com

Attaching package: 㤼㸱data.table㤼㸲

The following objects are masked from 㤼㸱package:dplyr㤼㸲:

    between, first, last

The following object is masked from 㤼㸱package:purrr㤼㸲:

    transpose
library(readxl)

#Install and load older versions of the following packages
#remove.packages("REAT")
#install_version("REAT", version = "2.1.1", repos = "http://cran.us.r-project.org")
library(REAT)

Attaching package: 㤼㸱REAT㤼㸲

The following object is masked from 㤼㸱package:data.table㤼㸲:

    shift
library(forecast)
Registered S3 method overwritten by 'quantmod':
  method            from
  as.zoo.data.frame zoo 
# Change the presentation of decimal numbers to 4 and avoid scientific notation
options(prompt="R> ", digits=8, scipen=999)

1 Import the master dataste

Via the tidyverse package

library(readr)
long_master_nona <- read_csv("01-raw-data/noNA_long_all_data_master_health_violence_services_education.csv", locale = locale(encoding = "ISO-8859-1"),    col_types = cols(NDVr = col_double(), 
       eb_ndvr = col_double(), eb_npir = col_double(), 
       nimr = col_double(), Litr= col_double(), 
        nmrpr = col_double(), nmpr = col_double() ))
wide_master_nona <- read_csv("01-raw-data/noNA_wide_data_master_health_violence_services_education.csv", locale = locale(encoding = "ISO-8859-1"))


cv<- read_csv(  "03-data/code04_timeseries_cv.csv")
cv<-cv[,-1]

cvy<- read_csv(  "03-data/code04_timeseries_cv_yearly.csv")
cvy<-cvy[,-1]

2 Preparing the dataset

Selecting variables needed

wide_master_nona

3 how many municiplaities will achieve the SDGs target by 2022

is the speed of convergence changing over time?


nmr<- wide_master_nona %>% 
  select(2:5,starts_with("eb_nmr"))
nmr
alpha=c()
lambda=c()
beta_coefficient=c()
half_life=c()
p_value=c()
years=c()
list_beta=list()
year_final=c()
for (i in 1:12) {
  tab<-nmr%>% 
  select(5:20)
  tab<- tab %>% 
    select(i,i+4)
  name1<- as.character(colnames(tab)[1])
  name2<- as.character(colnames(tab)[2])
  colnames(tab)[1]<-"FY_yo"
  colnames(tab)[2]<-"FY_yt"
    tab
beta <- betaconv.ols (tab$FY_yo, i, tab$FY_yt, i+4,
                       beta.plot = FALSE,
                       beta.plotLine = TRUE,
                       beta.plotX = paste("Ln (non murder rate in", name1), 
                       beta.plotY = paste("Annual Growth Rate",name1,name2), 
                       beta.plotTitle = paste(name1,name2),
                      beta.plotLineCol = "purple",output.results = FALSE)
alpha[i]<-as.data.frame(beta[["abeta"]])[1,1]
beta_coefficient[i]<-as.data.frame(beta[["abeta"]])[2,1]
lambda[i]<-as.data.frame(beta[["abeta"]])[3,1]
half_life[i]<-as.data.frame(beta[["abeta"]])[4,1]
p_value[i]<-as.data.frame(beta[["abeta"]])[2,4]
years[i]<- paste(substr(name1,nchar(name1)-3,nchar(name1)),substr(name2,nchar(name2)-3,nchar(name2)),sep="-")
year_final[i]<- as.integer(substr(name2,nchar(name2)-3,nchar(name2)),sep="-")
list_beta[[i]]<- beta
}

nmr_beta<- data.frame(years,year_final, alpha,beta_coefficient,lambda, half_life,p_value)
nmr_beta
nmr_beta
nmr_beta %>% 
  #ggplot(aes(x=year_final, y=beta_coefficient))+
  ggplot(aes(x=year_final, y=alpha)) +
  geom_point()+
  geom_smooth(method="lm")

nmr_beta %>% 
  #ggplot(aes(x=year_final, y=beta_coefficient))+
  ggplot(aes(x=year_final, y=lambda)) +
  geom_point()+
  geom_smooth(method="lm")


nmr_beta %>% 
  ggplot(aes(x=year_final, y=beta_coefficient))+
  #ggplot(aes(x=year_final, y=lambda)) +
  geom_point()+
  geom_smooth(method="lm")


lm_nmr_beta <- lm(beta_coefficient~year_final, nmr_beta)
lm_nmr_beta %>%  tidy()
newd <- data.frame(year_final=2022)
beta_2022<- predict(lm_nmr_beta,newd)

lm_nmr_lambda <- lm(lambda~year_final, nmr_beta)
lm_nmr_lambda %>%  tidy()
newd <- data.frame(year_final=2022)
lambda_2022<- predict(lm_nmr_lambda,newd)

lm_nmr_alpha <- lm(alpha~year_final, nmr_beta)
lm_nmr_alpha %>%  tidy()
newd <- data.frame(year_final=2022)
alpha_2022<- predict(lm_nmr_alpha,newd)
alpha_2022
        1 
1.0397204 
beta_2022
          1 
-0.11288337 
lambda_2022
           1 
-0.030322844 
final_coeff<- nmr_beta %>%  select(-1)
final_coeff

4 saving estimates of coefficients over time

write.csv(final_coeff, "03-data/code04_table_pred.csv")

5 how many municiplaities will achieve the NMR SDGs target by 2022

#long_master_nona
long_master_nona %>% 
  select(1:6,eb_nmr) %>% 
  filter(year==2018) %>% 
  summarise(mean(eb_nmr))

#target 23,23 per 100.000 people

target<- 10000-(23.23/10)
target
[1] 9997.677
nmr_2018 <- long_master_nona %>% 
  select(code,year,eb_nmr) %>% 
  filter(year==2018) %>% 
  filter(eb_nmr < target)

nmr_2018

y2022=c()
y2022 <- exp(alpha_2022+((1+beta_2022)*log(nmr_2018$eb_nmr)))
#y2022

nmr_2018$NMr2022 <- y2022
nmr_2018 %>% 
  filter(NMr2022<target)

We would like to forecast the value of NMR for the year 2022 but having data up to 2018, that is h=4. we could try to use as a training set data from 2003 to 2014 in order to predidct the value of 2018 and compare it with the real value

nmr_beta_14<- nmr_beta %>% 
  filter(year_final<=2014)

nmr_beta_14
nmr_beta_14 %>% 
  #ggplot(aes(x=year_final, y=beta_coefficient))+
  ggplot(aes(x=year_final, y=alpha)) +
  geom_point()+
  geom_smooth(method="lm")

nmr_beta_14 %>% 
  #ggplot(aes(x=year_final, y=beta_coefficient))+
  ggplot(aes(x=year_final, y=lambda)) +
  geom_point()+
  geom_smooth(method="lm")


nmr_beta_14 %>% 
  ggplot(aes(x=year_final, y=beta_coefficient))+
  #ggplot(aes(x=year_final, y=lambda)) +
  geom_point()+
  geom_smooth(method="lm")


lm_nmr_beta_14 <- lm(beta_coefficient~year_final, nmr_beta_14)
lm_nmr_beta_14 %>%  tidy()
newd <- data.frame(year_final=2018)
beta_2018<- predict(lm_nmr_beta_14,newd)

lm_nmr_lambda <- lm(lambda~year_final, nmr_beta_14)
lm_nmr_lambda %>%  tidy()
newd <- data.frame(year_final=2018)
lambda_2018<- predict(lm_nmr_lambda,newd)

lm_nmr_alpha <- lm(alpha~year_final, nmr_beta_14)
lm_nmr_alpha %>%  tidy()
newd <- data.frame(year_final=2018)
alpha_2018<- predict(lm_nmr_alpha,newd)
alpha_2018
        1 
1.3045419 
beta_2018
          1 
-0.14163641 
lambda_2018
           1 
-0.070536311 

We can now compute the forecast for 2018 and compare it to the actual value

#long_master_nona

nmr_2018 <- wide_master_nona %>% 
  select(code,eb_nmr_2014, eb_nmr_2018) 

nmr_2018

y2018=c()
y2018 <- exp(alpha_2018+((1+beta_2018)*log(nmr_2018$eb_nmr_2014)))
#y2022

nmr_2018$fc2018 <- y2018
nmr_2018 <- nmr_2018 %>% 
  mutate(forecast_error=eb_nmr_2018-fc2018)
nmr_2018 %>% arrange(forecast_error)
NA
mean((nmr_2018$forecast_error)^2)
[1] 7.8302761

6 time series cross validation for h=4

nmr_beta
alphax=c()
betax=c()
lambdax=c()
nmr_beta
for (x in seq_along(2011:2018)) {
  ye=2007+(x-1)
  nmr_betax<- nmr_beta %>% 
  filter(year_final<=ye)

lm_nmr_betax <- lm(beta_coefficient~year_final, nmr_betax)
lm_nmr_betax %>%  tidy()
newd <- data.frame(year_final=ye+4)
beta_x4<- predict(lm_nmr_betax,newd)

lm_nmr_lambda <- lm(lambda~year_final, nmr_betax)
lm_nmr_lambda %>%  tidy()
newd <- data.frame(year_final=ye+4)
lambda_x4<- predict(lm_nmr_lambda,newd)

lm_nmr_alpha <- lm(alpha~year_final, nmr_betax)
lm_nmr_alpha %>%  tidy()
newd <- data.frame(year_final=ye+4)
alpha_x4<- predict(lm_nmr_alpha,newd)
alphax[x]= alpha_x4
betax[x]=beta_x4
lambda[x]=lambda_x4
 
}
alphax
[1] 7.80337836 1.54458092 1.28866776 1.90273287
[5] 2.70741957 1.49217308 0.57446011 1.30454185
nmr_xx <- wide_master_nona %>% 
  select(code,starts_with("eb_nmr")) 

nmr_xx

fc_nmr=c()

for (jj in 1:8) {
  
  fc_nmr <- exp(alphax[jj]+((1+betax[[jj]])*log(nmr_xx[[jj+5]])))
  
  nmr_xx<- cbind(nmr_xx, fc_nmr)
  colnames(nmr_xx)[ncol(nmr_xx)]<-paste("fc",colnames(nmr_xx)[jj+9],sep="")
  
}

nmr_xx
nmr_xxx<- nmr_xx %>% 
  select(10:25)
year=c(2011:2018)
forecast_error=c()
nmr_xxx
for (i in seq_along(year)) {
   forecast_error= (nmr_xxx[[i]]-nmr_xxx[[i+8]])^2
nmr_xxx<- cbind(nmr_xxx, forecast_error)
colnames(nmr_xxx)[ncol(nmr_xxx)]<- paste("for.error", as.character(year[i]), sep="")
   }
nmr_xxx
error<-nmr_xxx %>% 
  select(17:24)
rmsev<-mean(as.matrix(error))
rmsev= sqrt(rmsev)

7 new tables

#cv
#RMSE
#error
rmse<-error %>% 
  summarise_all(sum)
rmse<-sqrt(rmse/1120)
rmse

#MAE

mae_y <- sqrt(error)
#mae_y
mae_y<- mae_y%>% 
  summarise_all(sum)
mae_y<- mae_y/1120
mae_y

cvy
cv_yearly<- rbind(mae_y, rmse)

methodv=c("BETA (MAE)","BETA (RMSE)")
names=seq(2011,2018,1)
names= as.character(names)
colnames(cv_yearly)<-names
cv_yearly<- cv_yearly %>% 
  mutate(method=methodv) %>% 
  select(method, everything())
cv_yearly
cvy2<- rbind(cvy, cv_yearly)
write.csv(cvy2,  "03-data/code04_timeseries_cv_yearly.csv")

the RMSE is sqrt(6.1883245)

error
mae<-mean(as.matrix(sqrt(error)))
mae
[1] 1.6581373
cv<-rbind(cv, data.frame(method= c("Beta"), MAE= mae, RMSE=rmsev))
cv
write.csv(cv,  "03-data/code04_timeseries_cv.csv")

8 Improving the prediction of alpha and beta

nmr_beta 
nmr_beta %>% 
  #ggplot(aes(x=year_final, y=beta_coefficient))+
  ggplot(aes(x=year_final, y=alpha)) +
  geom_point()+
  geom_smooth(method="lm")

nmr_beta %>% 
  #ggplot(aes(x=year_final, y=beta_coefficient))+
  ggplot(aes(x=year_final, y=lambda)) +
  geom_point()+
  geom_smooth(method="lm")


nmr_beta %>% 
  ggplot(aes(x=year_final, y=beta_coefficient))+
  #ggplot(aes(x=year_final, y=lambda)) +
  geom_point()+
  geom_smooth(method="lm")

for forecasting nmr a prediction of beta and apha is needed can the forecasting of these coefficients be improved?

alpha_ts<- ts(nmr_beta$alpha, start=2007)
beta_ts<- ts(nmr_beta$beta_coefficient, start=2007)
autoplot(alpha_ts)

autoplot(beta_ts)


ggAcf(alpha_ts)

ggAcf(beta_ts)


fita_arima <- auto.arima(alpha_ts)
fitb_arima <- auto.arima(beta_ts)
fita_ets <- ets(alpha_ts)
fitb_ets <- ets(beta_ts)

as it can be seen below, beta and alpha may not be predicted using arima or ets models since the trend is not considered.

fita_arima %>% forecast(h=4) %>% autoplot()

fitb_arima %>% forecast(h=4) %>% autoplot()

fita_ets %>% forecast(h=4) %>% autoplot()

fitb_ets %>% forecast(h=4) %>% autoplot()

NA
NA
sessionInfo()
R version 4.0.4 (2021-02-15)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 19043)

Matrix products: default

locale:
[1] LC_COLLATE=English_United States.1252 
[2] LC_CTYPE=English_United States.1252   
[3] LC_MONETARY=English_United States.1252
[4] LC_NUMERIC=C                          
[5] LC_TIME=English_United States.1252    

attached base packages:
[1] stats     graphics  grDevices utils     datasets 
[6] methods   base     

other attached packages:
 [1] forecast_8.12     REAT_2.1.1       
 [3] readxl_1.3.1      data.table_1.12.8
 [5] broom_0.5.6       modelr_0.1.7     
 [7] forcats_0.5.0     stringr_1.4.0    
 [9] dplyr_1.0.2       purrr_0.3.4      
[11] readr_1.3.1       tidyr_1.0.3      
[13] tibble_3.0.1      ggplot2_3.3.0    
[15] tidyverse_1.3.0   knitr_1.28       
[17] ExPanDaR_0.5.3    devtools_2.3.0   
[19] usethis_1.6.1    

loaded via a namespace (and not attached):
 [1] nlme_3.1-152        fs_1.4.1           
 [3] xts_0.12-0          lubridate_1.7.8    
 [5] httr_1.4.1          rprojroot_1.3-2    
 [7] tools_4.0.4         backports_1.1.6    
 [9] R6_2.4.1            DT_0.13            
[11] mgcv_1.8-33         DBI_1.1.0          
[13] colorspace_1.4-1    nnet_7.3-15        
[15] withr_2.2.0         tidyselect_1.1.0   
[17] prettyunits_1.1.1   tictoc_1.0         
[19] processx_3.4.2      curl_4.3           
[21] compiler_4.0.4      cli_2.0.2          
[23] rvest_0.3.5         xml2_1.3.2         
[25] desc_1.2.0          labeling_0.3       
[27] tseries_0.10-47     scales_1.1.1       
[29] lmtest_0.9-37       fracdiff_1.5-1     
[31] quadprog_1.5-8      callr_3.4.3        
[33] askpass_1.1         digest_0.6.25      
[35] foreign_0.8-81      rio_0.5.16         
[37] pkgconfig_2.0.3     htmltools_0.4.0    
[39] sessioninfo_1.1.1   dbplyr_1.4.3       
[41] fastmap_1.0.1       TTR_0.23-6         
[43] htmlwidgets_1.5.1   rlang_0.4.7        
[45] quantmod_0.4.17     rstudioapi_0.11    
[47] shiny_1.4.0.2       farver_2.0.3       
[49] generics_0.0.2      zoo_1.8-8          
[51] jsonlite_1.7.1      zip_2.0.4          
[53] magrittr_1.5        Matrix_1.3-2       
[55] Rcpp_1.0.4.6        munsell_0.5.0      
[57] fansi_0.4.1         shinycssloaders_0.3
[59] lifecycle_0.2.0     stringi_1.4.6      
[61] pkgbuild_1.0.7      grid_4.0.4         
[63] parallel_4.0.4      promises_1.1.0     
[65] crayon_1.3.4        lattice_0.20-41    
[67] splines_4.0.4       haven_2.2.0        
[69] hms_0.5.3           ps_1.3.2           
[71] pillar_1.4.4        pkgload_1.0.2      
[73] urca_1.3-0          reprex_0.3.0       
[75] glue_1.4.0          remotes_2.1.1      
[77] vctrs_0.3.2         httpuv_1.5.2       
[79] testthat_2.3.2      cellranger_1.1.0   
[81] gtable_0.3.0        openssl_1.4.1      
[83] assertthat_0.2.1    xfun_0.22          
[85] openxlsx_4.1.5      mime_0.9           
[87] xtable_1.8-4        later_1.0.0        
[89] timeDate_3043.102   memoise_1.1.0      
[91] ellipsis_0.3.0     
LS0tDQp0aXRsZTogImNsYXNzaWNhbCBjb252ZXJnZW5jZSBmb3JlY2FzdGluZyBmb3Igbm1yIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGRmX3ByaW50OiBwYWdlZA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiAnNCcNCiAgaHRtbF9ub3RlYm9vazoNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBoaWdobGlnaHQ6IG1vbm9jaHJvbWUNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRoZW1lOiBjb3Ntbw0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgdG9jX2Zsb2F0Og0KICAgICAgY29sbGFwc2VkOiBubw0KICAgICAgc21vb3RoX3Njcm9sbDogbm8NCiAgcGRmX2RvY3VtZW50Og0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiAnNCcNCi0tLQ0KDQoNCmBgYHtyIHNldHVwfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFKQ0KbGlicmFyeShkZXZ0b29scykNCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkobW9kZWxyKQ0KbGlicmFyeShicm9vbSkNCmxpYnJhcnkoZGF0YS50YWJsZSkNCmxpYnJhcnkocmVhZHhsKQ0KDQojSW5zdGFsbCBhbmQgbG9hZCBvbGRlciB2ZXJzaW9ucyBvZiB0aGUgZm9sbG93aW5nIHBhY2thZ2VzDQojcmVtb3ZlLnBhY2thZ2VzKCJSRUFUIikNCiNpbnN0YWxsX3ZlcnNpb24oIlJFQVQiLCB2ZXJzaW9uID0gIjIuMS4xIiwgcmVwb3MgPSAiaHR0cDovL2NyYW4udXMuci1wcm9qZWN0Lm9yZyIpDQpsaWJyYXJ5KFJFQVQpDQpsaWJyYXJ5KGZvcmVjYXN0KQ0KDQojIENoYW5nZSB0aGUgcHJlc2VudGF0aW9uIG9mIGRlY2ltYWwgbnVtYmVycyB0byA0IGFuZCBhdm9pZCBzY2llbnRpZmljIG5vdGF0aW9uDQpvcHRpb25zKHByb21wdD0iUj4gIiwgZGlnaXRzPTgsIHNjaXBlbj05OTkpDQpgYGANCg0KIyBJbXBvcnQgdGhlIG1hc3RlciBkYXRhc3RlDQoNClZpYSB0aGUgYHRpZHl2ZXJzZWAgcGFja2FnZQ0KDQpgYGB7cn0NCmxpYnJhcnkocmVhZHIpDQpsb25nX21hc3Rlcl9ub25hIDwtIHJlYWRfY3N2KCIwMS1yYXctZGF0YS9ub05BX2xvbmdfYWxsX2RhdGFfbWFzdGVyX2hlYWx0aF92aW9sZW5jZV9zZXJ2aWNlc19lZHVjYXRpb24uY3N2IiwgbG9jYWxlID0gbG9jYWxlKGVuY29kaW5nID0gIklTTy04ODU5LTEiKSwgICAgY29sX3R5cGVzID0gY29scyhORFZyID0gY29sX2RvdWJsZSgpLCANCiAgICAgICBlYl9uZHZyID0gY29sX2RvdWJsZSgpLCBlYl9ucGlyID0gY29sX2RvdWJsZSgpLCANCiAgICAgICBuaW1yID0gY29sX2RvdWJsZSgpLCBMaXRyPSBjb2xfZG91YmxlKCksIA0KICAgICAgICBubXJwciA9IGNvbF9kb3VibGUoKSwgbm1wciA9IGNvbF9kb3VibGUoKSApKQ0Kd2lkZV9tYXN0ZXJfbm9uYSA8LSByZWFkX2NzdigiMDEtcmF3LWRhdGEvbm9OQV93aWRlX2RhdGFfbWFzdGVyX2hlYWx0aF92aW9sZW5jZV9zZXJ2aWNlc19lZHVjYXRpb24uY3N2IiwgbG9jYWxlID0gbG9jYWxlKGVuY29kaW5nID0gIklTTy04ODU5LTEiKSkNCg0KDQpjdjwtIHJlYWRfY3N2KCAgIjAzLWRhdGEvY29kZTA0X3RpbWVzZXJpZXNfY3YuY3N2IikNCmN2PC1jdlssLTFdDQoNCmN2eTwtIHJlYWRfY3N2KCAgIjAzLWRhdGEvY29kZTA0X3RpbWVzZXJpZXNfY3ZfeWVhcmx5LmNzdiIpDQpjdnk8LWN2eVssLTFdDQpgYGANCg0KIyBQcmVwYXJpbmcgdGhlIGRhdGFzZXQNCg0KU2VsZWN0aW5nIHZhcmlhYmxlcyBuZWVkZWQNCmBgYHtyfQ0Kd2lkZV9tYXN0ZXJfbm9uYQ0KYGBgDQoNCg0KIyBob3cgbWFueSBtdW5pY2lwbGFpdGllcyB3aWxsIGFjaGlldmUgdGhlIFNER3MgdGFyZ2V0IGJ5IDIwMjINCg0KaXMgdGhlIHNwZWVkIG9mIGNvbnZlcmdlbmNlIGNoYW5naW5nIG92ZXIgdGltZT8NCg0KYGBge3J9DQoNCm5tcjwtIHdpZGVfbWFzdGVyX25vbmEgJT4lIA0KICBzZWxlY3QoMjo1LHN0YXJ0c193aXRoKCJlYl9ubXIiKSkNCm5tcg0KYWxwaGE9YygpDQpsYW1iZGE9YygpDQpiZXRhX2NvZWZmaWNpZW50PWMoKQ0KaGFsZl9saWZlPWMoKQ0KcF92YWx1ZT1jKCkNCnllYXJzPWMoKQ0KbGlzdF9iZXRhPWxpc3QoKQ0KeWVhcl9maW5hbD1jKCkNCmZvciAoaSBpbiAxOjEyKSB7DQogIHRhYjwtbm1yJT4lIA0KICBzZWxlY3QoNToyMCkNCiAgdGFiPC0gdGFiICU+JSANCiAgICBzZWxlY3QoaSxpKzQpDQogIG5hbWUxPC0gYXMuY2hhcmFjdGVyKGNvbG5hbWVzKHRhYilbMV0pDQogIG5hbWUyPC0gYXMuY2hhcmFjdGVyKGNvbG5hbWVzKHRhYilbMl0pDQogIGNvbG5hbWVzKHRhYilbMV08LSJGWV95byINCiAgY29sbmFtZXModGFiKVsyXTwtIkZZX3l0Ig0KICAgIHRhYg0KYmV0YSA8LSBiZXRhY29udi5vbHMgKHRhYiRGWV95bywgaSwgdGFiJEZZX3l0LCBpKzQsDQogICAgICAgICAgICAgICAgICAgICAgIGJldGEucGxvdCA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgICAgICBiZXRhLnBsb3RMaW5lID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICAgYmV0YS5wbG90WCA9IHBhc3RlKCJMbiAobm9uIG11cmRlciByYXRlIGluIiwgbmFtZTEpLCANCiAgICAgICAgICAgICAgICAgICAgICAgYmV0YS5wbG90WSA9IHBhc3RlKCJBbm51YWwgR3Jvd3RoIFJhdGUiLG5hbWUxLG5hbWUyKSwgDQogICAgICAgICAgICAgICAgICAgICAgIGJldGEucGxvdFRpdGxlID0gcGFzdGUobmFtZTEsbmFtZTIpLA0KICAgICAgICAgICAgICAgICAgICAgIGJldGEucGxvdExpbmVDb2wgPSAicHVycGxlIixvdXRwdXQucmVzdWx0cyA9IEZBTFNFKQ0KYWxwaGFbaV08LWFzLmRhdGEuZnJhbWUoYmV0YVtbImFiZXRhIl1dKVsxLDFdDQpiZXRhX2NvZWZmaWNpZW50W2ldPC1hcy5kYXRhLmZyYW1lKGJldGFbWyJhYmV0YSJdXSlbMiwxXQ0KbGFtYmRhW2ldPC1hcy5kYXRhLmZyYW1lKGJldGFbWyJhYmV0YSJdXSlbMywxXQ0KaGFsZl9saWZlW2ldPC1hcy5kYXRhLmZyYW1lKGJldGFbWyJhYmV0YSJdXSlbNCwxXQ0KcF92YWx1ZVtpXTwtYXMuZGF0YS5mcmFtZShiZXRhW1siYWJldGEiXV0pWzIsNF0NCnllYXJzW2ldPC0gcGFzdGUoc3Vic3RyKG5hbWUxLG5jaGFyKG5hbWUxKS0zLG5jaGFyKG5hbWUxKSksc3Vic3RyKG5hbWUyLG5jaGFyKG5hbWUyKS0zLG5jaGFyKG5hbWUyKSksc2VwPSItIikNCnllYXJfZmluYWxbaV08LSBhcy5pbnRlZ2VyKHN1YnN0cihuYW1lMixuY2hhcihuYW1lMiktMyxuY2hhcihuYW1lMikpLHNlcD0iLSIpDQpsaXN0X2JldGFbW2ldXTwtIGJldGENCn0NCg0Kbm1yX2JldGE8LSBkYXRhLmZyYW1lKHllYXJzLHllYXJfZmluYWwsIGFscGhhLGJldGFfY29lZmZpY2llbnQsbGFtYmRhLCBoYWxmX2xpZmUscF92YWx1ZSkNCmBgYA0KDQpgYGB7cn0NCm5tcl9iZXRhDQpgYGANCg0KYGBge3J9DQpubXJfYmV0YQ0Kbm1yX2JldGEgJT4lIA0KICAjZ2dwbG90KGFlcyh4PXllYXJfZmluYWwsIHk9YmV0YV9jb2VmZmljaWVudCkpKw0KICBnZ3Bsb3QoYWVzKHg9eWVhcl9maW5hbCwgeT1hbHBoYSkpICsNCiAgZ2VvbV9wb2ludCgpKw0KICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIikNCm5tcl9iZXRhICU+JSANCiAgI2dncGxvdChhZXMoeD15ZWFyX2ZpbmFsLCB5PWJldGFfY29lZmZpY2llbnQpKSsNCiAgZ2dwbG90KGFlcyh4PXllYXJfZmluYWwsIHk9bGFtYmRhKSkgKw0KICBnZW9tX3BvaW50KCkrDQogIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKQ0KDQpubXJfYmV0YSAlPiUgDQogIGdncGxvdChhZXMoeD15ZWFyX2ZpbmFsLCB5PWJldGFfY29lZmZpY2llbnQpKSsNCiAgI2dncGxvdChhZXMoeD15ZWFyX2ZpbmFsLCB5PWxhbWJkYSkpICsNCiAgZ2VvbV9wb2ludCgpKw0KICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIikNCg0KbG1fbm1yX2JldGEgPC0gbG0oYmV0YV9jb2VmZmljaWVudH55ZWFyX2ZpbmFsLCBubXJfYmV0YSkNCmxtX25tcl9iZXRhICU+JSAgdGlkeSgpDQpuZXdkIDwtIGRhdGEuZnJhbWUoeWVhcl9maW5hbD0yMDIyKQ0KYmV0YV8yMDIyPC0gcHJlZGljdChsbV9ubXJfYmV0YSxuZXdkKQ0KDQpsbV9ubXJfbGFtYmRhIDwtIGxtKGxhbWJkYX55ZWFyX2ZpbmFsLCBubXJfYmV0YSkNCmxtX25tcl9sYW1iZGEgJT4lICB0aWR5KCkNCm5ld2QgPC0gZGF0YS5mcmFtZSh5ZWFyX2ZpbmFsPTIwMjIpDQpsYW1iZGFfMjAyMjwtIHByZWRpY3QobG1fbm1yX2xhbWJkYSxuZXdkKQ0KDQpsbV9ubXJfYWxwaGEgPC0gbG0oYWxwaGF+eWVhcl9maW5hbCwgbm1yX2JldGEpDQpsbV9ubXJfYWxwaGEgJT4lICB0aWR5KCkNCm5ld2QgPC0gZGF0YS5mcmFtZSh5ZWFyX2ZpbmFsPTIwMjIpDQphbHBoYV8yMDIyPC0gcHJlZGljdChsbV9ubXJfYWxwaGEsbmV3ZCkNCmFscGhhXzIwMjINCmJldGFfMjAyMg0KbGFtYmRhXzIwMjINCmBgYA0KDQpgYGB7cn0NCmZpbmFsX2NvZWZmPC0gbm1yX2JldGEgJT4lICBzZWxlY3QoLTEpDQpmaW5hbF9jb2VmZg0KYGBgDQoNCiMgc2F2aW5nIGVzdGltYXRlcyBvZiBjb2VmZmljaWVudHMgb3ZlciB0aW1lIA0KDQpgYGB7cn0NCndyaXRlLmNzdihmaW5hbF9jb2VmZiwgIjAzLWRhdGEvY29kZTA0X3RhYmxlX3ByZWQuY3N2IikNCmBgYA0KDQoNCiMgaG93IG1hbnkgbXVuaWNpcGxhaXRpZXMgd2lsbCBhY2hpZXZlIHRoZSBOTVIgU0RHcyB0YXJnZXQgYnkgMjAyMg0KDQoNCmBgYHtyfQ0KI2xvbmdfbWFzdGVyX25vbmENCmxvbmdfbWFzdGVyX25vbmEgJT4lIA0KICBzZWxlY3QoMTo2LGViX25tcikgJT4lIA0KICBmaWx0ZXIoeWVhcj09MjAxOCkgJT4lIA0KICBzdW1tYXJpc2UobWVhbihlYl9ubXIpKQ0KDQojdGFyZ2V0IDIzLDIzIHBlciAxMDAuMDAwIHBlb3BsZQ0KDQp0YXJnZXQ8LSAxMDAwMC0oMjMuMjMvMTApDQp0YXJnZXQNCg0Kbm1yXzIwMTggPC0gbG9uZ19tYXN0ZXJfbm9uYSAlPiUgDQogIHNlbGVjdChjb2RlLHllYXIsZWJfbm1yKSAlPiUgDQogIGZpbHRlcih5ZWFyPT0yMDE4KSAlPiUgDQogIGZpbHRlcihlYl9ubXIgPCB0YXJnZXQpDQoNCm5tcl8yMDE4DQoNCnkyMDIyPWMoKQ0KeTIwMjIgPC0gZXhwKGFscGhhXzIwMjIrKCgxK2JldGFfMjAyMikqbG9nKG5tcl8yMDE4JGViX25tcikpKQ0KI3kyMDIyDQoNCm5tcl8yMDE4JE5NcjIwMjIgPC0geTIwMjINCm5tcl8yMDE4ICU+JSANCiAgZmlsdGVyKE5NcjIwMjI8dGFyZ2V0KQ0KYGBgDQoNCg0KV2Ugd291bGQgbGlrZSB0byBmb3JlY2FzdCB0aGUgdmFsdWUgb2YgTk1SIGZvciB0aGUgeWVhciAyMDIyIGJ1dCBoYXZpbmcgZGF0YSB1cCB0byAyMDE4LCB0aGF0IGlzIGg9NC4NCndlIGNvdWxkIHRyeSB0byB1c2UgYXMgYSB0cmFpbmluZyBzZXQgZGF0YSBmcm9tIDIwMDMgdG8gMjAxNCBpbiBvcmRlciB0byBwcmVkaWRjdCB0aGUgdmFsdWUgb2YgMjAxOCBhbmQgY29tcGFyZSBpdCB3aXRoIHRoZSByZWFsIHZhbHVlDQoNCg0KYGBge3J9DQpubXJfYmV0YV8xNDwtIG5tcl9iZXRhICU+JSANCiAgZmlsdGVyKHllYXJfZmluYWw8PTIwMTQpDQoNCm5tcl9iZXRhXzE0DQpubXJfYmV0YV8xNCAlPiUgDQogICNnZ3Bsb3QoYWVzKHg9eWVhcl9maW5hbCwgeT1iZXRhX2NvZWZmaWNpZW50KSkrDQogIGdncGxvdChhZXMoeD15ZWFyX2ZpbmFsLCB5PWFscGhhKSkgKw0KICBnZW9tX3BvaW50KCkrDQogIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKQ0Kbm1yX2JldGFfMTQgJT4lIA0KICAjZ2dwbG90KGFlcyh4PXllYXJfZmluYWwsIHk9YmV0YV9jb2VmZmljaWVudCkpKw0KICBnZ3Bsb3QoYWVzKHg9eWVhcl9maW5hbCwgeT1sYW1iZGEpKSArDQogIGdlb21fcG9pbnQoKSsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIpDQoNCm5tcl9iZXRhXzE0ICU+JSANCiAgZ2dwbG90KGFlcyh4PXllYXJfZmluYWwsIHk9YmV0YV9jb2VmZmljaWVudCkpKw0KICAjZ2dwbG90KGFlcyh4PXllYXJfZmluYWwsIHk9bGFtYmRhKSkgKw0KICBnZW9tX3BvaW50KCkrDQogIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKQ0KDQpsbV9ubXJfYmV0YV8xNCA8LSBsbShiZXRhX2NvZWZmaWNpZW50fnllYXJfZmluYWwsIG5tcl9iZXRhXzE0KQ0KbG1fbm1yX2JldGFfMTQgJT4lICB0aWR5KCkNCm5ld2QgPC0gZGF0YS5mcmFtZSh5ZWFyX2ZpbmFsPTIwMTgpDQpiZXRhXzIwMTg8LSBwcmVkaWN0KGxtX25tcl9iZXRhXzE0LG5ld2QpDQoNCmxtX25tcl9sYW1iZGEgPC0gbG0obGFtYmRhfnllYXJfZmluYWwsIG5tcl9iZXRhXzE0KQ0KbG1fbm1yX2xhbWJkYSAlPiUgIHRpZHkoKQ0KbmV3ZCA8LSBkYXRhLmZyYW1lKHllYXJfZmluYWw9MjAxOCkNCmxhbWJkYV8yMDE4PC0gcHJlZGljdChsbV9ubXJfbGFtYmRhLG5ld2QpDQoNCmxtX25tcl9hbHBoYSA8LSBsbShhbHBoYX55ZWFyX2ZpbmFsLCBubXJfYmV0YV8xNCkNCmxtX25tcl9hbHBoYSAlPiUgIHRpZHkoKQ0KbmV3ZCA8LSBkYXRhLmZyYW1lKHllYXJfZmluYWw9MjAxOCkNCmFscGhhXzIwMTg8LSBwcmVkaWN0KGxtX25tcl9hbHBoYSxuZXdkKQ0KYWxwaGFfMjAxOA0KYmV0YV8yMDE4DQpsYW1iZGFfMjAxOA0KYGBgDQoNCg0KV2UgY2FuIG5vdyBjb21wdXRlIHRoZSBmb3JlY2FzdCBmb3IgMjAxOCBhbmQgY29tcGFyZSBpdCB0byB0aGUgYWN0dWFsIHZhbHVlDQoNCg0KYGBge3J9DQojbG9uZ19tYXN0ZXJfbm9uYQ0KDQpubXJfMjAxOCA8LSB3aWRlX21hc3Rlcl9ub25hICU+JSANCiAgc2VsZWN0KGNvZGUsZWJfbm1yXzIwMTQsIGViX25tcl8yMDE4KSANCg0Kbm1yXzIwMTgNCg0KeTIwMTg9YygpDQp5MjAxOCA8LSBleHAoYWxwaGFfMjAxOCsoKDErYmV0YV8yMDE4KSpsb2cobm1yXzIwMTgkZWJfbm1yXzIwMTQpKSkNCiN5MjAyMg0KDQpubXJfMjAxOCRmYzIwMTggPC0geTIwMTgNCm5tcl8yMDE4IDwtIG5tcl8yMDE4ICU+JSANCiAgbXV0YXRlKGZvcmVjYXN0X2Vycm9yPWViX25tcl8yMDE4LWZjMjAxOCkNCm5tcl8yMDE4ICU+JSBhcnJhbmdlKGZvcmVjYXN0X2Vycm9yKQ0KDQpgYGANCg0KDQpgYGB7cn0NCm1lYW4oKG5tcl8yMDE4JGZvcmVjYXN0X2Vycm9yKV4yKQ0KYGBgDQoNCg0KDQojICB0aW1lIHNlcmllcyBjcm9zcyB2YWxpZGF0aW9uIGZvciBoPTQNCmBgYHtyfQ0Kbm1yX2JldGENCmBgYA0KDQpgYGB7cn0NCmFscGhheD1jKCkNCmJldGF4PWMoKQ0KbGFtYmRheD1jKCkNCm5tcl9iZXRhDQpmb3IgKHggaW4gc2VxX2Fsb25nKDIwMTE6MjAxOCkpIHsNCiAgeWU9MjAwNysoeC0xKQ0KICBubXJfYmV0YXg8LSBubXJfYmV0YSAlPiUgDQogIGZpbHRlcih5ZWFyX2ZpbmFsPD15ZSkNCg0KbG1fbm1yX2JldGF4IDwtIGxtKGJldGFfY29lZmZpY2llbnR+eWVhcl9maW5hbCwgbm1yX2JldGF4KQ0KbG1fbm1yX2JldGF4ICU+JSAgdGlkeSgpDQpuZXdkIDwtIGRhdGEuZnJhbWUoeWVhcl9maW5hbD15ZSs0KQ0KYmV0YV94NDwtIHByZWRpY3QobG1fbm1yX2JldGF4LG5ld2QpDQoNCmxtX25tcl9sYW1iZGEgPC0gbG0obGFtYmRhfnllYXJfZmluYWwsIG5tcl9iZXRheCkNCmxtX25tcl9sYW1iZGEgJT4lICB0aWR5KCkNCm5ld2QgPC0gZGF0YS5mcmFtZSh5ZWFyX2ZpbmFsPXllKzQpDQpsYW1iZGFfeDQ8LSBwcmVkaWN0KGxtX25tcl9sYW1iZGEsbmV3ZCkNCg0KbG1fbm1yX2FscGhhIDwtIGxtKGFscGhhfnllYXJfZmluYWwsIG5tcl9iZXRheCkNCmxtX25tcl9hbHBoYSAlPiUgIHRpZHkoKQ0KbmV3ZCA8LSBkYXRhLmZyYW1lKHllYXJfZmluYWw9eWUrNCkNCmFscGhhX3g0PC0gcHJlZGljdChsbV9ubXJfYWxwaGEsbmV3ZCkNCmFscGhheFt4XT0gYWxwaGFfeDQNCmJldGF4W3hdPWJldGFfeDQNCmxhbWJkYVt4XT1sYW1iZGFfeDQNCiANCn0NCg0KDQpgYGANCg0KYGBge3J9DQphbHBoYXgNCmBgYA0KDQoNCmBgYHtyfQ0Kbm1yX3h4IDwtIHdpZGVfbWFzdGVyX25vbmEgJT4lIA0KICBzZWxlY3QoY29kZSxzdGFydHNfd2l0aCgiZWJfbm1yIikpIA0KDQpubXJfeHgNCg0KZmNfbm1yPWMoKQ0KDQpmb3IgKGpqIGluIDE6OCkgew0KICANCiAgZmNfbm1yIDwtIGV4cChhbHBoYXhbampdKygoMStiZXRheFtbampdXSkqbG9nKG5tcl94eFtbamorNV1dKSkpDQogIA0KICBubXJfeHg8LSBjYmluZChubXJfeHgsIGZjX25tcikNCiAgY29sbmFtZXMobm1yX3h4KVtuY29sKG5tcl94eCldPC1wYXN0ZSgiZmMiLGNvbG5hbWVzKG5tcl94eClbamorOV0sc2VwPSIiKQ0KICANCn0NCg0Kbm1yX3h4DQpgYGANCg0KDQpgYGB7cn0NCm5tcl94eHg8LSBubXJfeHggJT4lIA0KICBzZWxlY3QoMTA6MjUpDQp5ZWFyPWMoMjAxMToyMDE4KQ0KZm9yZWNhc3RfZXJyb3I9YygpDQpubXJfeHh4DQpmb3IgKGkgaW4gc2VxX2Fsb25nKHllYXIpKSB7DQogICBmb3JlY2FzdF9lcnJvcj0gKG5tcl94eHhbW2ldXS1ubXJfeHh4W1tpKzhdXSleMg0Kbm1yX3h4eDwtIGNiaW5kKG5tcl94eHgsIGZvcmVjYXN0X2Vycm9yKQ0KY29sbmFtZXMobm1yX3h4eClbbmNvbChubXJfeHh4KV08LSBwYXN0ZSgiZm9yLmVycm9yIiwgYXMuY2hhcmFjdGVyKHllYXJbaV0pLCBzZXA9IiIpDQogICB9DQoNCmBgYA0KDQpgYGB7cn0NCm5tcl94eHgNCmVycm9yPC1ubXJfeHh4ICU+JSANCiAgc2VsZWN0KDE3OjI0KQ0Kcm1zZXY8LW1lYW4oYXMubWF0cml4KGVycm9yKSkNCnJtc2V2PSBzcXJ0KHJtc2V2KQ0KYGBgDQoNCiMgbmV3IHRhYmxlcw0KDQpgYGB7cn0NCiNjdg0KI1JNU0UNCiNlcnJvcg0Kcm1zZTwtZXJyb3IgJT4lIA0KICBzdW1tYXJpc2VfYWxsKHN1bSkNCnJtc2U8LXNxcnQocm1zZS8xMTIwKQ0Kcm1zZQ0KDQojTUFFDQoNCm1hZV95IDwtIHNxcnQoZXJyb3IpDQojbWFlX3kNCm1hZV95PC0gbWFlX3klPiUgDQogIHN1bW1hcmlzZV9hbGwoc3VtKQ0KbWFlX3k8LSBtYWVfeS8xMTIwDQptYWVfeQ0KDQpjdnkNCmN2X3llYXJseTwtIHJiaW5kKG1hZV95LCBybXNlKQ0KDQptZXRob2R2PWMoIkJFVEEgKE1BRSkiLCJCRVRBIChSTVNFKSIpDQpuYW1lcz1zZXEoMjAxMSwyMDE4LDEpDQpuYW1lcz0gYXMuY2hhcmFjdGVyKG5hbWVzKQ0KY29sbmFtZXMoY3ZfeWVhcmx5KTwtbmFtZXMNCmN2X3llYXJseTwtIGN2X3llYXJseSAlPiUgDQogIG11dGF0ZShtZXRob2Q9bWV0aG9kdikgJT4lIA0KICBzZWxlY3QobWV0aG9kLCBldmVyeXRoaW5nKCkpDQpjdl95ZWFybHkNCmN2eTI8LSByYmluZChjdnksIGN2X3llYXJseSkNCndyaXRlLmNzdihjdnkyLCAgIjAzLWRhdGEvY29kZTA0X3RpbWVzZXJpZXNfY3ZfeWVhcmx5LmNzdiIpDQpgYGANCg0KDQoNCg0KDQp0aGUgUk1TRSBpcyAgc3FydCg2LjE4ODMyNDUpDQoNCmBgYHtyfQ0KZXJyb3INCm1hZTwtbWVhbihhcy5tYXRyaXgoc3FydChlcnJvcikpKQ0KbWFlDQpgYGANCg0KYGBge3J9DQpjdjwtcmJpbmQoY3YsIGRhdGEuZnJhbWUobWV0aG9kPSBjKCJCZXRhIiksIE1BRT0gbWFlLCBSTVNFPXJtc2V2KSkNCmN2DQpgYGANCg0KYGBge3J9DQp3cml0ZS5jc3YoY3YsICAiMDMtZGF0YS9jb2RlMDRfdGltZXNlcmllc19jdi5jc3YiKQ0KYGBgDQoNCg0KIyBJbXByb3ZpbmcgdGhlIHByZWRpY3Rpb24gb2YgYWxwaGEgYW5kIGJldGEgDQpgYGB7cn0NCm5tcl9iZXRhIA0Kbm1yX2JldGEgJT4lIA0KICAjZ2dwbG90KGFlcyh4PXllYXJfZmluYWwsIHk9YmV0YV9jb2VmZmljaWVudCkpKw0KICBnZ3Bsb3QoYWVzKHg9eWVhcl9maW5hbCwgeT1hbHBoYSkpICsNCiAgZ2VvbV9wb2ludCgpKw0KICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIikNCm5tcl9iZXRhICU+JSANCiAgI2dncGxvdChhZXMoeD15ZWFyX2ZpbmFsLCB5PWJldGFfY29lZmZpY2llbnQpKSsNCiAgZ2dwbG90KGFlcyh4PXllYXJfZmluYWwsIHk9bGFtYmRhKSkgKw0KICBnZW9tX3BvaW50KCkrDQogIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKQ0KDQpubXJfYmV0YSAlPiUgDQogIGdncGxvdChhZXMoeD15ZWFyX2ZpbmFsLCB5PWJldGFfY29lZmZpY2llbnQpKSsNCiAgI2dncGxvdChhZXMoeD15ZWFyX2ZpbmFsLCB5PWxhbWJkYSkpICsNCiAgZ2VvbV9wb2ludCgpKw0KICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIikNCmBgYA0KDQoNCmZvciBmb3JlY2FzdGluZyBubXIgYSBwcmVkaWN0aW9uIG9mIGJldGEgYW5kIGFwaGEgaXMgbmVlZGVkIGNhbiB0aGUgZm9yZWNhc3Rpbmcgb2YgdGhlc2UgY29lZmZpY2llbnRzIGJlIGltcHJvdmVkPw0KDQoNCmBgYHtyfQ0KYWxwaGFfdHM8LSB0cyhubXJfYmV0YSRhbHBoYSwgc3RhcnQ9MjAwNykNCmJldGFfdHM8LSB0cyhubXJfYmV0YSRiZXRhX2NvZWZmaWNpZW50LCBzdGFydD0yMDA3KQ0KYXV0b3Bsb3QoYWxwaGFfdHMpDQphdXRvcGxvdChiZXRhX3RzKQ0KDQpnZ0FjZihhbHBoYV90cykNCmdnQWNmKGJldGFfdHMpDQoNCmZpdGFfYXJpbWEgPC0gYXV0by5hcmltYShhbHBoYV90cykNCmZpdGJfYXJpbWEgPC0gYXV0by5hcmltYShiZXRhX3RzKQ0KZml0YV9ldHMgPC0gZXRzKGFscGhhX3RzKQ0KZml0Yl9ldHMgPC0gZXRzKGJldGFfdHMpDQoNCg0KYGBgDQoNCmFzIGl0IGNhbiBiZSBzZWVuIGJlbG93LCBiZXRhIGFuZCBhbHBoYSBtYXkgbm90IGJlIHByZWRpY3RlZCB1c2luZyBhcmltYSBvciBldHMgbW9kZWxzIHNpbmNlIHRoZSB0cmVuZCBpcyBub3QgY29uc2lkZXJlZC4gDQoNCg0KYGBge3J9DQpmaXRhX2FyaW1hICU+JSBmb3JlY2FzdChoPTQpICU+JSBhdXRvcGxvdCgpDQpmaXRiX2FyaW1hICU+JSBmb3JlY2FzdChoPTQpICU+JSBhdXRvcGxvdCgpDQpmaXRhX2V0cyAlPiUgZm9yZWNhc3QoaD00KSAlPiUgYXV0b3Bsb3QoKQ0KZml0Yl9ldHMgJT4lIGZvcmVjYXN0KGg9NCkgJT4lIGF1dG9wbG90KCkNCg0KDQpgYGANCg0KDQpgYGB7cn0NCnNlc3Npb25JbmZvKCkNCmBgYA==